# [十一]Spring AOP - 代理入口类
# 是否生成代理
当一个bean 实例化完成后,会判断该 bean 是否生成代理: AOP 的入口,找到
doCreateBean()方法所在类 org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// AOP 的入口方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
进入
initializeBean()方法所在类 org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// AOP入口的具体生产 代理实例方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
}
}
知识点
applyBeanPostProcessorsAfterInitialization() 方法是一个 BeanPostProcessor 接口的运用,initializeBean 方法我们都知道是一个bean 实例化完成后做的操作,而这个代理实例生成也是在bean 实例化完成后做的操作。
进入
applyBeanPostProcessorsAfterInitialization()方法所在类 org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory
/**
* TODO: 当bean 实例化完成后的 代理包装
*/
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
进入
BeanPostProcessor类的postProcessAfterInitialization()方法找到实现类
AbstractAutoProxyCreator的postProcessAfterInitialization()方法所在类 org.springframework.aop.framework.autoproxy.
AbstractAutoProxyCreator
/**
* TODO: 验证
*/
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
进入
wrapIfNecessary()方法所在类 org.springframework.aop.framework.autoproxy.
AbstractAutoProxyCreator
/**
* TODO: 创建当前bean的代理,核心方法
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 创建当前bean的代理,如果这个bean有advice的话,重点看,重要程度5
// 得到所有的可用于拦截当前 bean 的 advisor、advice、interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果有切面,则生成该bean的代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 把被代理对象bean实例封装到SingletonTargetSource对象中
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
进入
getAdvicesAndAdvisorsForBean()方法,继续进入findEligibleAdvisors()方法所在类 org.springframework.aop.framework.autoproxy.
AbstractAdvisorAutoProxyCreator
/**
* TODO:查找@Aspectj注解的类,核心方法
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到候选的切面,其实就是一个寻找有@Aspectj注解的过程,
// 把工程中所有有这个注解的类封装成Advisor返回
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 判断候选的切面是否作用在当前beanClass上面,就是一个匹配过程。
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//对有@Order@Priority进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
知识点
如何查找当前bean 的切面
1、从Spring中查找所有的切面
- ①、首先找到所有的
BeanDefinition对象对应的beanName,反射拿到对应的 Class 对象,判断该类上面是否有@Aspect注解,有则是我们要找的; - ② 、 然后循环该Class 里面的除了
@PointCut注解的方法,找到方法上的Around.class,Before.class,After.class,AfterReturning.class,AfterThrowing.class注解,并且把注解里面的信息,比如表达式、argNames、注解类型等信息封装成对象AspectJAnnotation; - ③ 、接着创建
pointCut对象,把注解对象中的表达式设置到pointCut对象中; - ④、最后就是创建
Advice对象,根据不同的注解类型创建出不同的Advice对象,对象如 下 :AspectJAroundAdvice,AspectJAfterAdvice, AspectJAfterThrowingAdvice,AspectJMethodBeforeAdvice, AspectJAfterReturningAdvice 最终把注解对应的Advice对象和pointCut对象封装成Advisor对象。
- ①、首先找到所有的
2、找到拦截当前bean的切面
- 从收集到的所有切面中,每一个切面都会有
pointCut来进行模块匹配,其实这个过程就是一个匹配过程,看看pointCut表达式中的内容是否包含了当前 bean,如果包含了,那么这个 bean 就有切面,就会生成代理。
- 从收集到的所有切面中,每一个切面都会有
# 代理类的调用
//创建当前bean的代理,如果这个bean有advice的话,重点看,重要程度5
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//如果有切面,则生成该bean的代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//把被代理对象bean实例封装到SingletonTargetSource对象中
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
当
getAdvicesAndAdvisorsForBean()方法拦截到有advice的类,如果返回的Object[] specificInterceptors数组不为空,最终会执行到createProxy(),这个方法就会生成 bean的代理实例。进入
createProxy方法所在类 org.springframework.aop.framework.
AbstractAutoProxyCreator
/**
* TODO : 创建代理实例
* @param beanClass 类对象
* @param beanName bean 名字
* @param specificInterceptors 拦截到的所有的 advisors
* @param targetSource 具体类实现的信息(被代理实例)
* @return
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建代理工厂实例
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
// proxyTargetClass 是否对类进行代理,而不是对接口进行代理,
// 设置为true时,使用CGLib代理。
proxyFactory.setProxyTargetClass(true);
}
else {
// 1. 有接口的,循环调用:proxyFactory.addInterface(ifc);
// 2. 没有接口的,调用:proxyFactory.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 把 advice 类型的增强包装成 advisor 切面
// 返回匹配了当前 bean 的 advisors 数组
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
// 用来控制代理工厂被配置后,是否还允许修改代理的配置,默认为false
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 获取代理实例
return proxyFactory.getProxy(getProxyClassLoader());
}
进入
buildAdvisors方法所在类 org.springframework.aop.framework.
AbstractAutoProxyCreator
/**
* TODO : 包装成 advisor 切面的过程
*/
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// 自定义 MethodInterceptor 拿到 AnnotationAwareAspectJAutoProxyCreator
// 对象调用 setInterceptorNames方法
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
if (logger.isTraceEnabled()) {
int nrOfCommonInterceptors = commonInterceptors.length;
int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
// 对自定义的 advice要进行包装,把 advice包装成 advisor对象,切面对象
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
执行完
buildAdvisors方法,返回匹配了当前 bean 的 advisors 数组继续执行
createProxy方法,进入getProxy()方法所在类 org.springframework.aop.framework.
ProxyFactory
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
进入
createAopProxy()方法所在类 org.springframework.aop.framework.
ProxyCreatorSupport
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 创建一个 AopProxy 的实例
return getAopProxyFactory().createAopProxy(this);
}
创建
createAopProxy()方法 之前,需要拿到一个AopProxyFactory实例进入
getAopProxyFactory()方法所在类 org.springframework.aop.framework.
ProxyCreatorSupport
public class ProxyCreatorSupport extends AdvisedSupport {
private AopProxyFactory aopProxyFactory;
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
public AopProxyFactory getAopProxyFactory() {
return this.aopProxyFactory;
}
}
很明显,拿到的
this.aopProxyFactory的值,来自构造方法new DefaultAopProxyFactory()进入
DefaultAopProxyFactory类的createAopProxy()方法所在类 org.springframework.aop.framework.
DefaultAopProxyFactory
/**
* TODO : 创建 AopProxy 代理实例
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果要代理的类本身就是接口,创建一个新的 JDK代理实例,多例模式
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否则使用 Cglib 代理
// ObjenesisCglibAopProxy 在Spring4.0 就有了
return new ObjenesisCglibAopProxy(config);
}
else {
// 如果有接口,创建一个新的 JDK代理实例,多例模式
return new JdkDynamicAopProxy(config);
}
}
知识点
- 如果被代理的目标类实现了一个或多个自定义的接口,那么就会使用 JDK 动态代理;
- 如果被代理的目标类没有实现任何接口,会使用 CGLIB 实现代理;
- 如果设置了
proxyTargetClass="true",那么都会使用 CGLIB生成代理;
总结:
JDK 动态代理基于接口,所以只有接口中的方法会被增强(因为代理类已经继承了Proxy),而 CGLIB 基于类继承,如果目标类中的方法使用了final 或private 关键字来修饰,是不能被增强的。
当被代理的目标类是基于JDK的动态代理,进入
JdkDynamicAopProxy()的构造方法所在类 org.springframework.aop.framework.
JdkDynamicAopProxy
// 代理工厂对象(保存这个AOP代理所有的配置信息 包括所有的增强器等等)
private final AdvisedSupport advised;
//......省略无关代码
/**
* TODO : 根据参数中指定的配置(config)构造一个新的JdkDynamicAopProxy
*/
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
// 校验:必须有至少一个增强器和目标实例
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
到此,已经创建好了
AopProxy,返回到最初的getProxy()方法
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
拿到了
AopProxy,接着可以调用到了getProxy()方法进入
getProxy()最核心的方法所在类 org.springframework.aop.framework.
JdkDynamicAopProxy
/**
* TODO : 创建JDK动态代理实例
*/
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
/**
* TODO : 查找接口(advised 是代理工厂对象)
* 我们看到最终代理的接口就是这里返回的所有接口们(除了我们自己的接口,还有Spring默认的一些接口)
* 大致过程如下:
* 1、获取目标对象自己实现的接口(最终肯定都会被代理的)
* 2、是否添加`SpringProxy`这个接口:目标对象实现对就不添加了,没实现过就添加true
* 3、是否新增`Adviced`接口,注意不是Advice通知接口。 实现过就不实现了,
* 没实现过并且advised.isOpaque()=false就添加(默认是会添加的)
* 4、是否新增DecoratingProxy接口。传入的参数decoratingProxy为true,
* 并且没实现过就添加(显然这里,首次进来是会添加的)
* 5、代理类的接口一共是目标对象的接口+上面三个接口SpringProxy、Advised、DecoratingProxy
* (SpringProxy是个标记接口而已,其余的接口都有对应的方法的)
* 备注:DecoratingProxy 这个接口是 Spring4.3后才提供
*/
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 第三个参数传的 this,处理器就是当前类(实现了 InvocationHandler 接口)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
拿到代理对象调用,以 jdk 动态代理为例(Cglib 是一样的调用逻辑)。 当发生代理对象调用时,会调用到实现了 invocationHandler 接口的类,这个类就
JdkDynamicAopProxy,然后会调用到该类的 invoke 方法。
进入
invoke()方法所在类 org.springframework.aop.framework.
JdkDynamicAopProxy
说明
JdkDynamicAopProxy 本身实现了InvocationHandler 接口和AopProxy 接口所以 JdkDynamicAopProxy实现的InvocationHandler.invoker()方法就是Proxy 对象回调的方法。实现的AopProxy.getProxy()方法就是通过JDK动态代理生成的代理对象,传递的InvocationHandler 对象就是 JdkDynamicAopProxy 自身。这就是动态代理了,切面的业务就是在 invoke()方法中体现的。具体业务在源码中体现。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
// 从代理工厂中拿到 TargetSource 对象,该对象包装了被代理实例 bean
// 因为 InvocationHandler 持久的就是 targetSource,最终通过 getTarget 拿到目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 被代理对象的 equals方法和 hashCode方法是不能被代理的,不会走切面
// 所以此处做了处理 :
// equalsDefined为false(表示自己没有定义过 equals方法) 那就交给代理去比较
// hashCode同理,只要你自己没有实现过此方法,那就交给代理类处理
// 需要注意的是:这里统一指的是,如果接口上有此方法,但是你自己并没有实现 equals和 hashCode
// 方法,那就走AOP这里的实现
// 如过接口上没有定义此方法,只是实现类里自己 @Override了 HashCode,那是无效的,
// 就不做特殊处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
// DecoratingProxy的方法和Advised接口的方法都是最终调用了config,也就是this.advised去执行的
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
// 这个是最终该方法的返回值
Object retVal;
// 是否暴露代理对象,默认false可配置为true,如果暴露就意味着允许在线程内共享代理对象,
// 注意这是在线程内,也就是说同一线程的任意地方都能通过 AopContext 获取该代理对象,
// 这里缓存一份代理对象在 oldProxy
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 通过目标源获取目标对象,这个 target 就是目标对象(被代理实例)
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取作用在这个方法上的所有拦截器链
//会根据切点表达式去匹配这个方法。因此其实每个方法都会进入这里,只是有很多方法的拦截器链是空的
//从代理工厂中拿过滤器链 Object是一个 MethodInterceptor类型的对象,其实就是一个advice对象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果该方法没有执行链,则说明这个方法不需要被拦截,则直接反射调用
if (chain.isEmpty()) {
// 若拦截器为空,那就直接调用目标方法了
// 对参数进行适配:主要处理一些数组类型的参数,看是表示一个参数还是表示多个参数
// (可变参数最终到此都是数组类型,所以最好是需要一次适配)
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 直接通过反射调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建一个 invocation ,此处为 ReflectiveMethodInvocation 最终是通过它,
// 去执行前置加强、后置加强等逻辑
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 此处会执行所有的拦截器链 交给Spring AOP的 MethodInvocation 去处理。
// 其实现还是 Spring 的 ReflectiveMethodInvocation
retVal = invocation.proceed();
}
// Massage return value if necessary.
// 获取返回值的类型
Class<?> returnType = method.getReturnType();
// 判断条件,如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给 retVal
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
// 返回 null,并且还不是 Void类型,抛出异常
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
// 释放目标对象(被代理实例)
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
// 把老的代理对象重新 set进去
AopContext.setCurrentProxy(oldProxy);
}
}
}
知识点
- 除了实现类里自己写的方法(接口上没有的),其余方法统一都会进入代理得
invoke()方法里面。只是invoke上做了很多特殊处理,比如DecoratingProxy和Advised等等的方法,都是直接执行了。 object的方法中,被代理对象的equals方法和hashCode方法是不能被代理的,不会被增强,但是toString()方法会被增强(不确定AdvisedSupport#methodCache这个字段事什么时候把toString()方法缓存上的,打断点都没跟踪上)- 生成出来的代理对象,Spring默认都给你实现了接口:
SpringProxy、DecoratingProxy、Advised
# 创建代理的过程
- 1、创建代理工厂对象 ProxyFactory
- 2、切面对象重新包装,会把自定义的 MethodInterceptor 类型的类包装成 Advisor 切面类并加入到代理工厂中
- 3、根据proxyTargetClass 参数和是否实现接口来判断是采用 jdk 代理还是cglib 代理
- 4、创建代理对象,并且把代理工厂对象传递到 jdk 和 cglib 中,注意这里的代理对象和 jdk 类和 cglib 类是一一对应的。
# AOP问题汇总
问题一
实际生成的动态代理在哪里?
参考答案
生成的动态代理($Proxy0)是在JVM内存中的,一般情况是,先把java文件编译成class文件,然后类加载器加载这个class字节码文件,从而让JVM可以生成这个类的对象。但动态代理是,在内存中生成这些字节码,然后再正常地加载字节码,生成对象。
问题二
一个类中的方法如果有代理实例,那么这个代理实例会被IOC容器管理吗?
参考答案
问题三
AOP 拦截器调用如何实现的?
参考答案
如果是JDK实现的代理对象就会通过InvocationHandler 来完成拦截器回调,如果是CGLIB 就通过DynamicAdvisedInterceptor 来完成回调。
扩展阅读
通过AopProxy 对象封装target 目标对象之后,ProxyFactoryBean方法得到的对象已经是一个AopProxy代理对象了,在ProxyFactoryBean 中配置的target目标对象不会让应用直接调用其方法的实现,对target目标对象的方法调用会被AopProxy代理对象拦截,对于不同的AopProxy代理对象生成方式,会使用不同的拦截回调入口。对于 JDK的AopProxy代理对象,使用的是InvocationHander的invoker 回调入口。对于CGLIB的AopProxy代理对象,使用的是设置好的callbak 回调,在这里callback回调中,对于AOP的实现是通过DynamicAdvisedInterceptor 来完成的,DynamicAdvisedInterceptor 的回调入口是 intercept 方法。
问题四
Aspect 注解的类搜集方法的时候,为什么只循环没有@Pointcut 注解的方法?
参考答案
因为@Pointcut 只是切点表达式,不是通知方法
问题五
为什么依赖注入到三级缓存的是代理实例,而不是当前bean实例本身?
参考答案
因为Spring遵循了开闭原则,对修改关闭,对扩展开发,由于很多时候我们并不需要bean实例本身,而是需要修改后的实例,这样通过获取代理对象实例,可以更好的执行业务逻辑。
问题六
为什么实例化之前自定义代理保存到了三级缓存,拿到的却是bean实例本身?
参考答案
问题七
如何自定义一个拦截器链,添加到现在有的连接器链中?
参考答案
实现MethodInterceptor接口